package com.powernode.dispatch.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.powernode.common.constant.RedisConstant;
import com.powernode.dispatch.client.XxlJobClient;
import com.powernode.dispatch.mapper.OrderJobMapper;
import com.powernode.dispatch.service.NewOrderService;
import com.powernode.map.client.LocationFeignClient;
import com.powernode.model.entity.dispatch.OrderJob;
import com.powernode.model.enums.OrderStatus;
import com.powernode.model.form.map.SearchNearByDriverForm;
import com.powernode.model.vo.dispatch.NewOrderTaskVo;
import com.powernode.model.vo.map.NearByDriverVo;
import com.powernode.model.vo.order.NewOrderDataVo;
import com.powernode.order.client.OrderInfoFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Resource
    private OrderJobMapper orderJobMapper;


    @Resource
    private XxlJobClient xxlJobClient;
    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;

    @Resource
    private LocationFeignClient locationFeignClient;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 1.根据订单id查询当前订单任务
     * 2.若没有则插入数据库
     * @param newOrderTaskVo
     * @return
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo){
        //1.根据订单id查询当前订单任务
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getOrderId,newOrderTaskVo.getOrderId());
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);

        //2.若没有则插入数据库
        if (orderJob == null) {
            //将任务添加到xxl-job
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "", "0 0/1 * * * ?", "新订单任务 id:" + newOrderTaskVo.getOrderId());

            //添加数据
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setJobId(jobId);
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));//参数

            orderJobMapper.insert(orderJob);
        }

        return orderJob.getJobId();
    }


    /**
     * 1.查询任务参数
     * 2.查询订单状态
     * 3.搜索附近配送员
     * 4.给配送员派单
     * @param jobId
     * @return
     */
    @Override
    public Boolean executeTask(Long jobId) {
        //1.查询任务参数
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getJobId,jobId);
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        if (orderJob == null) {
            //订单被配送员接单后，删除了orderJob中的订单数据
            return true;
        }

        //将数据库中的json数据转成NewOrderTaskVo对象
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);

        //查询订单状态 若订单已被配送员接单，则停止调度，否则继续调度
        Integer orderStatus = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId()).getData();
        if(orderStatus.intValue() != OrderStatus.WAITING_ACCEPT.getStatus()){
            //停止调度
            xxlJobClient.stopJob(jobId);
            //xxlJobClient.removeJob(jobId);
            return true;
        }



        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        //起始位置
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        //距离
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());

        //查询符合条件的配送员
        List<NearByDriverVo> nearByDriverVoList = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();

        //将配送员数据放入redis
        nearByDriverVoList.forEach(driver -> {
            //获取配送员id  防止重复推送订单
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST + newOrderTaskVo.getOrderId();
            Boolean flag = redisTemplate.opsForSet().isMember(repeatKey, driver.getDriverId());
            if(!flag){
                //该配送员还没有推送过订单,现在将配送员数据放入redis
                //记录该配送员信息，防止重复推送订单
                redisTemplate.opsForSet().add(repeatKey, driver.getDriverId());
                //过期时间16分钟
                redisTemplate.expire(repeatKey, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);

                //构建配送员派单信息保存到redis的list
                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                BeanUtils.copyProperties(newOrderTaskVo, newOrderDataVo);

                String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();

                redisTemplate.opsForList().leftPush(key, JSONObject.toJSONString(newOrderDataVo));
                //过期时间
                redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME, TimeUnit.HOURS);
            }
        });

        return true;
    }


    /**
     * 配送员端查询redis中的订单数据
     */
    @Override
    public List<NewOrderDataVo> findNewOrderData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();

        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        Long size = redisTemplate.opsForList().size(key);
        if (size > 0) {
            //有配送员的订单
            for (int i = 0; i < size ; i++) {
                String content = (String)redisTemplate.opsForList().leftPop(key);
                //将json转成NewOrderDataVo对象
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);

                list.add(newOrderDataVo);
            }
        }

        return list;
    }


    /**
     * 情况redis中的配送订单数据
     */
    @Override
    public Boolean clearNewOrderData(Long driverId) {
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        redisTemplate.delete(key);
        return true;
    }
}
